package cn.aitrox.ry.service.auth.service.impl;

import cn.aitrox.ry.bean.CommonPageInfo;
import cn.aitrox.ry.bean.RespResult;
import cn.aitrox.ry.common.bean.Like;
import cn.aitrox.ry.constant.CommonConstant;
import cn.aitrox.ry.enumtype.RespCodeEnum;
import cn.aitrox.ry.service.auth.dao.AuthPermissionDao;
import cn.aitrox.ry.service.auth.dao.AuthRoleDao;
import cn.aitrox.ry.service.auth.dao.AuthRolePermissionDao;
import cn.aitrox.ry.service.auth.dao.AuthUserRoleDao;
import cn.aitrox.ry.service.auth.dto.permission.out.AuthPermissionDetailDto;
import cn.aitrox.ry.service.auth.dto.role.in.AuthRoleCreateInDto;
import cn.aitrox.ry.service.auth.dto.role.in.AuthRoleSearchInDto;
import cn.aitrox.ry.service.auth.dto.role.in.AuthRoleUpdateInDto;
import cn.aitrox.ry.service.auth.dto.role.out.AuthRoleDetailDto;
import cn.aitrox.ry.service.auth.entity.AuthPermissionEntity;
import cn.aitrox.ry.service.auth.entity.AuthRoleEntity;
import cn.aitrox.ry.service.auth.entity.AuthRolePermissionEntity;
import cn.aitrox.ry.service.auth.po.role.RoleQueryParamPo;
import cn.aitrox.ry.service.auth.service.AuthRoleService;
import cn.aitrox.ry.util.ArrayUtil;
import com.github.pagehelper.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class AuthRoleServiceImpl implements AuthRoleService {

    @Autowired
    private AuthRoleDao authRoleDao;

    @Autowired
    private AuthRolePermissionDao authRolePermissionDao;

    @Autowired
    private AuthPermissionDao authPermissionDao;

    @Autowired
    private AuthUserRoleDao authUserRoleDao;

    @Transactional
    @Override
    public RespResult<Integer> create(AuthRoleCreateInDto input) {
        String name = input.getName();
        List<Integer> permissionIds = input.getPermissionIds();

        // 校验名称是否重复
        AuthRoleEntity authRoleEntity = authRoleDao.findOne(new AuthRoleEntity(null, name));
        if (null != authRoleEntity) {
            return RespResult.secByError(RespCodeEnum.EXISTED.getCode(), "角色名称已存在");
        }

        // 校验资源ID是否存在
        if (!ArrayUtil.isEmpty(permissionIds)) {
            List<AuthPermissionEntity> permissionEntityList = authPermissionDao.findByIds(permissionIds.toArray(), null);
            List<Integer> permissionIdListInDB = permissionEntityList.stream().map(AuthPermissionEntity::getId).collect(Collectors.toList());
            List<Integer> notExistPermissionIds = permissionIds.stream().filter(permissionId -> !permissionIdListInDB.contains(permissionId)).collect(Collectors.toList());
            if (!ArrayUtil.isEmpty(notExistPermissionIds)) {
                return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "资源不存在: " + StringUtils.joinWith(CommonConstant.DEFAULT_SEPARATOR, notExistPermissionIds.toArray()));
            }
        }


        // 创建role和 role_permission
        authRoleEntity = new AuthRoleEntity(null, name);
        authRoleDao.insertSelective(authRoleEntity);
        Integer roleId = authRoleEntity.getId();

        List<AuthRolePermissionEntity> authPermissionResourceEntityList = permissionIds.stream().map(permissionId -> new AuthRolePermissionEntity(null, roleId, permissionId)).collect(Collectors.toList());

        authRolePermissionDao.batchInsert(authPermissionResourceEntityList);

        // 返回permissionId
        return RespResult.ok(roleId);
    }

    @Transactional
    @Override
    public RespResult update(AuthRoleUpdateInDto input) {
        // 校验权限是否存在
        AuthRoleEntity authRoleEntity = authRoleDao.findById(input.getId());
        if (null == authRoleEntity) {
            return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "角色不存在");
        }

        // 校验权限名称是否存在
        if (null != input.getName()) {
            AuthRoleEntity authRoleEntityByName = authRoleDao.findOne(new AuthRoleEntity(null, input.getName()));
            if (null != authRoleEntityByName && !input.getId().equals(authRoleEntityByName.getId())) {
                return RespResult.secByError(RespCodeEnum.EXISTED.getCode(), "角色名称已存在");
            }
        }

        // permission_resource的删除、新增
        if (!ArrayUtil.isEmpty(input.getPermissionIds())) {
            // 校验资源ID是否存在
            List<AuthPermissionEntity> permissionEntityList = authPermissionDao.findByIds(input.getPermissionIds().toArray(), null);
            List<Integer> permissionIdListInDB = permissionEntityList.stream().map(AuthPermissionEntity::getId).collect(Collectors.toList());
            List<Integer> notExistPermissionIdIds = input.getPermissionIds().stream().filter(permissionId -> !permissionIdListInDB.contains(permissionId)).collect(Collectors.toList());
            if (!ArrayUtil.isEmpty(notExistPermissionIdIds)) {
                return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "权限不存在: " + StringUtils.joinWith(CommonConstant.DEFAULT_SEPARATOR, notExistPermissionIdIds.toArray()));
            }

            List<AuthRolePermissionEntity> rolePermissionList = authRolePermissionDao.findByCondition(new AuthRolePermissionEntity(null, input.getId(), null), null);
            List<Integer> permissionIdsInDB = rolePermissionList.stream().map(AuthRolePermissionEntity::getPermissionId).collect(Collectors.toList());

            // 传参有，但是数据库中没有的 就是新增的
            List<Integer> permissionIdsAdd = input.getPermissionIds().stream().filter(permissionId -> !permissionIdsInDB.contains(permissionId)).collect(Collectors.toList());

            // 数据库有，但是传参中没有的 就是删除的
            List<Integer> permissionIdsRemove = permissionIdsInDB.stream().filter(permissionId -> !input.getPermissionIds().contains(permissionId)).collect(Collectors.toList());

            if (!ArrayUtil.isEmpty(permissionIdsRemove)) {
                authRolePermissionDao.deleteByRoleIdPermissionIds(input.getId(), permissionIdsRemove);
            }

            if (!ArrayUtil.isEmpty(permissionIdsAdd)) {
                authRolePermissionDao.batchInsert(permissionIdsAdd.stream().map(permissionId -> new AuthRolePermissionEntity(null, input.getId(), permissionId)).collect(Collectors.toList()));
            }
        }

        // 更新 permission
        if (null != input.getName()) {
            AuthRoleEntity roleUpdate = new AuthRoleEntity(input.getId(), input.getName());
            authRoleDao.updateByIdSelective(roleUpdate);
        }

        return RespResult.ok();
    }

    @Transactional
    @Override
    public RespResult delete(Integer id) {
        // 删除role、role_permission、user_role
        AuthRoleEntity roleEntity = authRoleDao.findById(id);
        if (null == roleEntity) {
            return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "角色不存在");
        }
        authRoleDao.deleteById(id);
        authRolePermissionDao.deleteByRoleIds(Arrays.asList(id));
        authUserRoleDao.deleteByRoleIds(Arrays.asList(id));
        return RespResult.ok();
    }

    @Override
    public RespResult<AuthRoleDetailDto> read(Integer id) {
        AuthRoleEntity roleEntity = authRoleDao.findById(id);
        if (null == roleEntity) {
            return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "角色不存在");
        }
        List<AuthPermissionDetailDto> permissionDetailList = null;
        List<AuthRolePermissionEntity> rolePermissionEntityList = authRolePermissionDao.findByCondition(new AuthRolePermissionEntity(null, id, null), null);
        if (!ArrayUtil.isEmpty(rolePermissionEntityList)) {
            List<Integer> permissionIds = rolePermissionEntityList.stream().map(AuthRolePermissionEntity::getPermissionId).collect(Collectors.toList());
            List<AuthPermissionEntity> permissionEntityList = authPermissionDao.findByIds(permissionIds.toArray(), null);
            permissionDetailList = permissionEntityList.stream().map(x -> new AuthPermissionDetailDto(x.getId(), x.getName(), null, x.getCreateTime(), x.getUpdateTime())).collect(Collectors.toList());
        }
        return RespResult.ok(new AuthRoleDetailDto(roleEntity.getId(), roleEntity.getName(), roleEntity.getCreateTime(), roleEntity.getUpdateTime(), permissionDetailList));
    }

    @Override
    public RespResult validRoleExist(List<Integer> roleIds) {
        if (!ArrayUtil.isEmpty(roleIds)) {
            // 校验角色ID是否存在\
            List<AuthRoleEntity> authRoleEntityList = authRoleDao.findByIds(roleIds.toArray(), null);
            List<Integer> roleIdsInDB = authRoleEntityList.stream().map(AuthRoleEntity::getId).collect(Collectors.toList());
            List<Integer> notExistRoleIds = roleIds.stream().filter(roleId -> !roleIdsInDB.contains(roleId)).collect(Collectors.toList());
            if (!ArrayUtil.isEmpty(notExistRoleIds)) {
                return RespResult.secByError(RespCodeEnum.NOT_EXIST.getCode(), "角色不存在: " + StringUtils.joinWith(CommonConstant.DEFAULT_SEPARATOR, notExistRoleIds.toArray()));
            }
        }
        return RespResult.ok();
    }

    @Override
    public CommonPageInfo<AuthRoleDetailDto> search(AuthRoleSearchInDto input) {
        PageInfo<AuthRoleEntity> pageInfo = authRoleDao.searchByParam(input.getPage(), input.getPageSize(), new RoleQueryParamPo(Like.joinLikeKeyword(input.getName())));
        if (!ArrayUtil.isEmpty(pageInfo.getList())) {
            return new CommonPageInfo(pageInfo.getTotal(), pageInfo.getPages(), null);
        }

        List<Integer> roleIdList = pageInfo.getList().stream().map(AuthRoleEntity::getId).collect(Collectors.toList());
        List<AuthRolePermissionEntity> rolePermissionEntityList = authRolePermissionDao.findByRoleIds(roleIdList);
        List<Integer> permissionIdList = rolePermissionEntityList.stream().map(AuthRolePermissionEntity::getPermissionId).distinct().collect(Collectors.toList());
        List<AuthPermissionEntity> permissionEntityList = authPermissionDao.findByIds(permissionIdList.toArray(), null);

        Map<Integer, List<Integer>> roleIdPermissionIdListMap = rolePermissionEntityList.stream().collect(Collectors.groupingBy(AuthRolePermissionEntity::getRoleId, Collectors.mapping(AuthRolePermissionEntity::getPermissionId, Collectors.toList())));

        List<AuthRoleDetailDto> list = pageInfo.getList().stream().map(x -> {
            List<AuthPermissionDetailDto> permissionList = null;
            List<Integer> permissionIdByRole = roleIdPermissionIdListMap.get(x.getId());
            if (!ArrayUtil.isEmpty(permissionIdByRole)) {
                List<AuthPermissionEntity> permissionByRole = permissionEntityList.stream().filter(permissionId -> permissionIdByRole.contains(permissionId)).collect(Collectors.toList());
                permissionList = permissionByRole.stream().map(y -> new AuthPermissionDetailDto(y.getId(), y.getName(), null, y.getCreateTime(), y.getUpdateTime())).collect(Collectors.toList());
            }
            return new AuthRoleDetailDto(x.getId(), x.getName(), x.getCreateTime(), x.getUpdateTime(), permissionList);
        }).collect(Collectors.toList());
        return new CommonPageInfo(pageInfo.getTotal(), pageInfo.getPages(), list);
    }

}
